package uebung08;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;

import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;

import tools.ColorConversions;
import tools.Derivative;
import tools.Gauss;
import crap.Pair;

public class Hough03 {
	public static void main(String[] args) {
		final double[] threshes = {0.8, 0.85, 0.9};
		for (int z = 0; z<3; z++)
		try {
			
			final BufferedImage bi = ImageIO.read(Hough03.class.getClassLoader().getResourceAsStream("res/schienen.jpg"));
			int[] lum = ColorConversions.getFastLuminance(bi.getRGB(0, 0, bi.getWidth(), bi.getHeight(), new int[bi.getWidth()*bi.getHeight()], 0, bi.getWidth()), new int[bi.getWidth()*bi.getHeight()]);
			
			int size = bi.getWidth()*bi.getHeight(), wCut = bi.getWidth(), hCut = bi.getHeight();
			final int w = bi.getWidth(), h = bi.getHeight(); //, size = w*h;
			
			lum = Gauss.gaussXY(lum, w, h, 1.6, new int[lum.length]);
			
			double[] gxy = new double[wCut * hCut];

			int[] dX = Derivative.dx(lum, w, h, new int[size]), dY = Derivative.dy(lum, w, h, new int[size]), abs = new int[size], roundedAngles = new int[size];

			for (int i = 0; i < size; i++) {
				abs[i] = (Math.abs(dX[i]) + Math.abs(dY[i])) / 2;
				gxy[i] = (dX[i] == 0 ? dY[i] == 0 ? 0 : (Math.PI / 2.) : Math.atan(dY[i] / (double) dX[i]));
			}

			double maxAbs = 0;
			for (int i = 0; i < size; i++) {
				maxAbs = Math.max(abs[i], maxAbs);
			}

			for (int i = 0; i < size; i++) {
				int rgb = (int)(abs[i]*255/maxAbs); // > 1 ? 255 : 0;
				lum[i] = rgb << 16 | rgb << 8 | rgb | 0xFF000000;
			}
			final int angle_resolution = 360, distance_resolution = 640;
			final double maxR = Math.hypot(bi.getWidth(), bi.getHeight())*2, oneOverMaxR = 1/maxR;
			
			double[] houghVotes = new double[angle_resolution*distance_resolution];
			
			int[] pH = new int[angle_resolution*distance_resolution];

			final ArrayList<Pair<Point2D, Point2D>> lines = new ArrayList<Pair<Point2D, Point2D>>();
			final ArrayList<Pair<Point2D, Point2D>> drawlines = new ArrayList<Pair<Point2D, Point2D>>();

			/*** hough voting **/
			for (int i = 0; i < size; i++) {
				if ((lum[i] & 0xFF) != 0) {
					int temp = 0;
					for (double theta = 0, stepTheta = Math.PI/(double)angle_resolution; theta < Math.PI; theta+=stepTheta, temp++) {
						
						int y = i / w, x = i % w;
						double r = (maxR / 2. + y * Math.cos(theta) + x * Math.sin(theta))*oneOverMaxR;
						houghVotes[temp + ((int) (r*distance_resolution) * angle_resolution)]++;
					}
				}
			}
			// normalization
			double max = Double.NEGATIVE_INFINITY;
			for (int i = 0; i < pH.length; i++) {
			
				max = Math.max(max, houghVotes[i]);
			}
			System.out.println(max);
			for (int i = 0; i < pH.length; i++) {
				int rgb = (int) ((houghVotes[i] / max) * 255);
				pH[i] = rgb << 16 | rgb << 8 | rgb | 0xFF000000;
			}

			int[] pH2 = new int[pH.length];
			{
				int size2 = pH.length, w2 = angle_resolution;
				for (int i = 0; i < pH.length; i++) {
					int right = (size2 + (i + 1)) % size2, left = (size2 + (i - 1))
							% size2, down = (size2 + (i + w2)) % size2, up = (size2 + (i - w2))
							% size2;
					int upright = (size2 + (i + 1 - w2)) % size2, downleft = (size2 + (i - 1 + w2))
							% size2, downright = (size2 + (i + w2 + 1))
							% size2, upleft = (size2 + (i - w2 - 1))
							% size2;
					pH2[i] = 0;
					if (houghVotes[i] < houghVotes[right] || houghVotes[i] < houghVotes[left]
							|| houghVotes[i] < houghVotes[upright]
							|| houghVotes[i] < houghVotes[upleft]
							|| houghVotes[i] < houghVotes[down]
							|| houghVotes[i] < houghVotes[up]
							|| houghVotes[i] < houghVotes[downright]
							|| houghVotes[i] < houghVotes[downleft])
						;
					else
//						if (houghVotes[i]>max*0.95)
							pH2[i] = pH[i];
					
				}

			}

			final double scale = 1000;
			for (int i = 0; i < houghVotes.length; i++) {
				if ((houghVotes[i]) > max*threshes[z]) {
					double degree = ((i % angle_resolution) / (double) angle_resolution) * 180;
					double theta = Math.toRadians(degree);
					double r = ((i / angle_resolution ) / (double)distance_resolution)*maxR - maxR / 2.;
					double y = r * Math.cos(theta), x = r * Math.sin(theta);
					double rx = scale * (y) + x, ry = scale * -x + (y);
					double dx = scale * -(y) + x, dy = scale * x + (y);
					Pair<Point2D, Point2D> pair = new Pair<Point2D, Point2D>(
							new Point2D.Double(x, y), new Point2D.Double(
									dx, dy));
					lines.add(pair);
					pair = new Pair<Point2D, Point2D>(new Point2D.Double(
							rx, ry), new Point2D.Double(dx, dy));
					drawlines.add(pair);
				}
			}
			bi.setRGB(0, 0, w,h, lum, 0,w);
			final BufferedImage show = new BufferedImage(angle_resolution, distance_resolution, BufferedImage.TYPE_INT_ARGB);
			show.setRGB(0,0,angle_resolution, distance_resolution, pH, 0, angle_resolution);
			
//			ImageIO.write(show, "PNG", new File("1001x1001houghtransform.png"));
			
			JFrame ff = new JFrame();
			ff.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			
			ff.add(new JComponent() {
				{setPreferredSize(new Dimension(bi.getWidth(), bi.getHeight()));}
				Line2D line = new Line2D.Double();
				@Override
				public void paint(Graphics g) {
				
					super.paint(g);
					Graphics2D g2 = (Graphics2D)g;
					g2.drawImage(bi, 0, 0, this);
					g2.setColor(Color.red);
					for (Pair<Point2D, Point2D> p : drawlines) {
						line.setLine(p.a, p.b);
						g2.draw(line);
					}
				}
			});
			
			ff.pack();
			ff.setVisible(true);
			
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}
}
